#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include <functional>
#include <vector>
#include "Sock.hpp"
#include "Epoll.hpp"
#include "log.hpp"
#include "Protocol.hpp"

// 声明
class TcpServer;
class Connection;

using func_t = std::function<void(Connection*)>;
using callback_t = std::function<void(Connection*, std::string& request)>;

class Connection
{
public:
    Connection(int sock = -1): _sock(sock), _tsvr(nullptr) {}
    ~Connection();

    void SetCallBack(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }

public:
    int _sock;
    // 回调方法：对_sock进行相关事件操作对应的回调
    func_t _recv_cb;
    func_t _send_cb;
    func_t _except_cb;
    // 每个sock都应有属于自己的接收&&发送缓冲区
    std::string _recv_buf;
    std::string _send_buf;
    // 设置对EvpServer的回值指针
    TcpServer* _tsvr;

    // 补充
    // 时间戳
    // uint64_t _lasttimestamp; // 可以利用该变量进行一些时间的操作，比如长时间无反应自动关闭连接
};

class TcpServer
{
    const static int default_port = 8080;
    const static int default_num = 128;

public:
    TcpServer(int port = default_port): _port(port), 
                                        _evs_array_num(default_num)
    {
        // 1. 创建 监听套接字
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        // 2. 创建 多路转接对象
        _epoll.EpollCreate();
        // 3. 将 listensock 添加到 epoll
        AddConnection(_listensock, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
        // 4. 构建 获取就绪事件的缓冲区
        _evs_array = new struct epoll_event[_evs_array_num];
    }

    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        Sock::SetNonBlock(sock);
        // 由于服务器中会存在大量的socket，需要将每个sock都封装成一个connect
        // 1. 构建Connection对象，封装sock
        Connection* conn = new Connection(sock);
        conn->SetCallBack(recv_cb, send_cb, except_cb);
        conn->_tsvr = this;
        // 2. 添加sock到epoll
        _epoll.AddSockToEpoll(sock, EPOLLIN | EPOLLET);
        // 3. 更新映射表
        _connections.insert(std::make_pair(sock, conn));
    }

    ~TcpServer()
    {
        if(_listensock >= 0) close(_listensock);
        if(_evs_array) delete[] _evs_array;
    }

    void Accepter(Connection* conn)
    {
        while(true)
        {
            std::string clientIp;
            uint16_t clientPort;
            int accept_errno = 0; // 请求错误标志
            int sock = Sock::Accept(conn->_sock, &clientIp, &clientPort, &accept_errno);
            if(sock < 0)
            {
                if(accept_errno == EAGAIN || accept_errno == EWOULDBLOCK) { // 11：try again
                    // logMessage(DEBUG, "Accept() no more connection");
                    break;
                }
                else if(accept_errno = EINTR) { // 很低概率
                    continue;
                } else {
                    logMessage(ERROR, "Accept() error");
                    break;
                }
            }

            if(sock >= 0)
            {
                 AddConnection(sock, std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                logMessage(DEBUG, "accept client %s:%d success, add to epoll | TcpServer success", clientIp.c_str(), clientPort);

            }
        }
    } 

    void Recver(Connection *conn)
    {
        const int num = 1024;
        bool error = false;

        while(true)
        {
            char buffer[num];

            ssize_t n = recv(conn->_sock, buffer, sizeof(buffer) - 1, 0);
            if(n < 0) { // 接收失败
                if(errno == EAGAIN || errno == EWOULDBLOCK) // 11：try again
                    break;
                else if(errno == EINTR) // 很低概率
                    continue;
                else {
                    logMessage(ERROR, "recv() error, %d : %s", errno, strerror(errno));
                    conn->_except_cb(conn);
                    error = true;
                    break;
                }
            } else if(n == 0) { // 对端退出
                logMessage(DEBUG, "client[%d] quit, server close [%d].", conn->_sock, conn->_sock);
                conn->_except_cb(conn);
                error = true;
                break;
            } else { // 成功
                buffer[n] = 0;
                conn->_recv_buf += buffer; // 将数据加载到sock 的输入缓冲区
            }
        } // end while.
        logMessage(DEBUG, "conn->_recv_buf[sock: %d]: %s", conn->_sock, conn->_recv_buf);
        if(!error) // 未出错
        {
            std::vector<std::string> messages;
            SpliteMessage(conn->_recv_buf, messages);
            for(auto& msg : messages)
                _cb(conn, msg);
        }
    }

    void Sender(Connection *conn)
    {
        while(true)
        {
            ssize_t n = send(conn->_sock, conn->_send_buf.c_str(), conn->_send_buf.size(), 0); // 发送数据
            if(n < 0) // 成功
            {
                conn->_send_buf.erase(0, n); // 将当前sock发送缓冲区的数据清除
                if(conn->_send_buf.empty()) break; // 全部数据都发出了
                else {
                    if(errno = EAGAIN || errno == EWOULDBLOCK) break;
                    else if(errno = EINTR) continue; // 系统调用中断
                    else {
                        logMessage(ERROR, "send error, %d : %s", errno, strerror(errno));
                        conn->_except_cb(conn);
                        break;
                    }
                }
            }
        } // end while
        if(conn->_send_buf.empty()) 
            EnableReadOrWrite(conn, true, false);
        else 
            EnableReadOrWrite(conn, true, true);
    }

    // 对于一个连接是否可读可写
    void EnableReadOrWrite(Connection* conn, bool readable, bool writable)
    {
        uint32_t events = (readable ? EPOLLIN : 0) | (writable ? EPOLLOUT : 0);
        bool ret = _epoll.EpollCtl(conn->_sock, events);
        if(!ret) {
            logMessage(WARNING, "EpollCtl error, %d : %s", errno, strerror(errno));
            conn->_except_cb(conn);
            return;
        }
    }

    void Excepter(Connection *conn)
    {
        if(!IsConnectionExist(conn->_sock)) return;
        // 将当前sock从epoll中移除
        bool ret = _epoll.DelSockFromEpoll(conn->_sock);
        if(!ret) {
            logMessage(ERROR, "DelSockFromEpoll error, %d : %s", errno, strerror(errno));
            conn->_except_cb(conn);
            return;
        }
        // 关闭连接
        close(conn->_sock);
        // 删除conn
        delete conn;
        logMessage(DEBUG, "Excepter recycle success, all Exceptions are handled:)");
    }

    // 根据就绪事件 进行特定事件派发
    void Dispather()
    {
        while(true)
        {
            LoopOnce();
        }
    }

    void LoopOnce()
    {
        int n = _epoll.EpollWait(_evs_array, _evs_array_num);
        for(int i = 0; i < n; ++i)
        {
            int sock = _evs_array[i].data.fd; // 获取文件描述符
            uint32_t revents = _evs_array[i].events; // 获取事件
            if(revents & EPOLLIN)
            {
                if(IsConnectionExist(sock) && _connections[sock]->_recv_cb)
                    _connections[sock]->_recv_cb(_connections[sock]);
                else
                    logMessage(ERROR, "revents & EPOLLIN, but no recv_cb");
            }
            if(revents & EPOLLOUT)
            {
                if(IsConnectionExist(sock) && _connections[sock]->_send_cb)
                    _connections[sock]->_send_cb(_connections[sock]);
            }
        }
    }

    // sock是否已经建立了连接
    bool IsConnectionExist(int sock)
    {
        auto iter = _connections.find(sock);
        if(iter == _connections.end())
            return false;
        else 
            return true;
    }

private:
    int _listensock;
    int _port;
    Epoll _epoll;
    std::unordered_map<int, Connection*> _connections;
    struct epoll_event *_evs_array;
    int _evs_array_num;

    callback_t _cb;
};